using System;
using QQZiFramework;
using QQZiFramework.Membership;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using System.Text.RegularExpressions;
using System.Collections;
using System.IO;
using log4net;
using log4net.Repository;
using QQZiFramework.Modals;
using QQZiFramework.MQ;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using QQZiFramework.Mvc;

namespace QQZiCore.Mvc
{
    public class OEMMemberShip : QQZiFramework.Mvc.WebHostMemberShip
    {
        static List<OEMMemberShip> membershipList;

        static readonly object lockobj = new object();

        public static OEMInfo GetOEM(string name)
        {
            if (name == null) throw new ArgumentNullException("name");
            name = name.ToLower();
            return OEMList.Find(X => X.Name.ToLower() == name);
        }

        public static OEMMemberShip GetInstance(string oem, bool throwNull = true)
        {
            lock (lockobj)
            {
                if (membershipList == null)
                {
                    using (DBContext context = new DBContext())
                    {
                        Init(context);
                    }
                }
            }
            OEMMemberShip memberShip = membershipList.Find(X => X.OEM.Name.ToLower() == oem.ToLower());
            if (memberShip == null && throwNull) throw new Exception("没有找到OEM:" + oem + "对应的MemberShip，请在Startup初始化！");
            return memberShip;
        }

        private void LoadOEMConfig(DBContext context)
        {
            context.LogMessage("加载" + OEM.Name + "配置", "Init");
            string appPath = QQZiFramework.Mvc.Extension.GetAppRootPath();
            string settingPath = Path.Combine(appPath, "settings");
            string jsonfile = Path.Combine(settingPath, OEM.Name + ".json");
            if (File.Exists(jsonfile))
            {
                using (System.IO.StreamReader file = new StreamReader(jsonfile, System.Text.Encoding.UTF8))
                {
                    string json = file.ReadToEnd();
                    OEM.AppSetting = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.Linq.JToken.Parse(json);
                }
                this.OEM.AppSetting.TryGetValue("Basic:Traditional", out m_responseTraditional);
            }
            else
            {
                context.LogMessage(OEM.Name + "没有配置文件", "Init");
            }


        }


        static Dictionary<string, Dictionary<string, QueryEntityConfig>> oemQueryMappings = new Dictionary<string, Dictionary<string, QueryEntityConfig>>();
        static Dictionary<string, Dictionary<string, QueryEntityConfig>> AdminOemQueryMappings = new Dictionary<string, Dictionary<string, QueryEntityConfig>>();

        private static Dictionary<string, QueryEntityConfig> appQueryMapping = null, AdminqueryMapping = null;

        /// <summary>
        /// Permission文件的内容
        /// </summary>  
        public override Dictionary<string, QueryEntityConfig> GetPermissionQueryMapping(DBContext context)
        {
            if (appQueryMapping == null || AdminqueryMapping == null)
            {
                appQueryMapping = LoadPermissionFile("Permission.json");
                AdminqueryMapping = LoadPermissionFile("Permission.Admin.json");
            }

            Dictionary<string, Dictionary<string, QueryEntityConfig>> whichDic;
            Dictionary<string, QueryEntityConfig> defaultMapping;
            string PermissionFileFirst = "Permission.";
            if (context.GetArgument<string>("Route-DATA-AREA") == "Admin")
            {
                PermissionFileFirst = "Permission.Admin.";
                whichDic = AdminOemQueryMappings;
                defaultMapping = AdminqueryMapping;
            }
            else
            {
                whichDic = oemQueryMappings;
                defaultMapping = appQueryMapping;
            }
            if (context.OEM == null) throw new Exception("OEM不正确");
            lock (whichDic)
            {
                if (whichDic.ContainsKey(context.OEM.Name)) return whichDic[context.OEM.Name];

                Dictionary<string, QueryEntityConfig> queryMapping = LoadPermissionFile(PermissionFileFirst + context.OEM.ExtName + ".json");
                //添加公共的Permission.json
                foreach (KeyValuePair<string, QueryEntityConfig> kv in defaultMapping)
                {
                    if (!queryMapping.ContainsKey(kv.Key)) queryMapping.Add(kv.Key, kv.Value);
                }
                whichDic.Add(context.OEM.Name, queryMapping);
                return queryMapping;
            }
        }

        private Dictionary<string, QueryEntityConfig> LoadPermissionFile(string fileName)
        {
            String filePath = Path.Combine(QQZiFramework.Mvc.Extension.GetAppRootPath(), fileName);
            if (File.Exists(filePath))
            {
                string json = QQZiFramework.Utility.ReadFile(filePath);
                if (string.IsNullOrEmpty(json)) return new Dictionary<string, QueryEntityConfig>();
                else return Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, QueryEntityConfig>>(json);
            }
            else return new Dictionary<string, QueryEntityConfig>();
        }

        public override void ClearCache(DBContext context)
        {
            DB_Config_lst = null;
            appQueryMapping = null;
            AdminqueryMapping = null;
            oemQueryMappings.Clear();
            AdminOemQueryMappings.Clear();
            LoadOEMConfig(context);
        }

        /// <summary>
        /// OEM商列表
        /// </summary>
        public static List<QQZiFramework.Modals.OEMInfo> OEMList { get { return OEMConfigs; } }
        protected static List<QQZiFramework.Modals.OEMInfo> OEMConfigs;

        public static void GetOEMList()
        {
            OEMConfigs = new List<OEMInfo>();
            IConfigurationSection section = QQZiFramework.Mvc.Extension.Configuration.GetSection("OEMSetting");
            foreach (IConfigurationSection oemItem in section.GetChildren())
            {
                QQZiFramework.Modals.OEMInfo oem = new OEMInfo() { Name = oemItem.Key.ToUpper() };
                oem.ConnectionStr = oemItem["Connection"];
                oem.ExtName = oemItem["ExtName"];
                if (oem.ExtName == null) oem.ExtName = oem.Name;
                oem.Title = oemItem["Title"];
                oem.ProviderName = oemItem["ProviderName"];
                OEMConfigs.Add(oem);
            }

        }

        public static void Init(DBContext context)
        {
            GetOEMList();
            membershipList = new List<OEMMemberShip>();
            string appPath = QQZiFramework.Mvc.Extension.GetAppRootPath();
            string wwwRootPath = QQZiFramework.Mvc.Extension.GetWWWRootPath();
            //BaseBusiness.Init(context, wwwRootPath);
            string settingPath = Path.Combine(appPath, "settings");
            if (!Directory.Exists(settingPath))
            {
                string oldPath = Path.Combine(wwwRootPath, "settings");
                if (Directory.Exists(oldPath))
                {
                    Directory.Move(oldPath, settingPath);
                }
            }
            string defaultLogFile = Path.Combine(appPath, "log4net.config");
            if (!File.Exists(defaultLogFile))
            {
                string oldPath = Path.Combine(wwwRootPath, "log4net.config");
                if (File.Exists(oldPath))
                {
                    File.Move(oldPath, defaultLogFile);
                }
            }

            foreach (OEMInfo oem in OEMList)
            {
                if (oem.ExtName == null) oem.ExtName = oem.Name;
                OEMMemberShip membership = new OEMMemberShip();
                membership.SetOEM(oem);
                membershipList.Add(membership);
                membership.LoadOEMConfig(context);
                string logConfigPath = Path.Combine(settingPath, oem.Name + ".log4net.config");
                FileInfo logFile = new FileInfo(logConfigPath);
                if (!logFile.Exists)
                {
                    logFile = new FileInfo(defaultLogFile);
                    System.Diagnostics.Debug.WriteLine(oem.Name + "没有对应的日志配置文件，使用默认的log4net.config");
                }
                if (logFile.Exists)
                {
                    var repository = LogManager.CreateRepository(oem.Name + "_Repository");
                    log4net.Config.XmlConfigurator.Configure(repository, logFile);
                }
                else
                {
                    throw new FileNotFoundException(logFile.FullName);
                }
                using (DBContext oemContext = membership.CreateDBContext())
                {
                    // oemContext.DeleteRedisItem("DB_Config_lst_init");
                    // oemContext.GetRedisDatabase().DeleteRedisItems("system_config*");
                    //oemContext.GetBusiness<VipProfitBLL>().ClearLevelCache();
                }



            }
        }
        private List<ConfigParam> DB_Config_lst;

        private ConfigParam GetDBConfigItem(DBContext oemContext, string name)
        {
            if (DB_Config_lst == null)
            {
                //是否存在配置表

                if (!oemContext.GetDBAccess().IsTableExists("A1_Configs")) DB_Config_lst = new List<ConfigParam>();
                else
                {
                    oemContext.WaitLock("DB_Config_lst_init", 60000);
                    DB_Config_lst = oemContext.QueryManySql<ConfigParam>("select * from A1_Configs");
                    oemContext.UnLockOne("DB_Config_lst_init");
                }
            }
            return DB_Config_lst.Find(x => x.ParamName == name);
        }


        OEMInfo oemInfo;

        public OEMInfo OEM { get { return oemInfo; } }

        private void SetOEM(OEMInfo oem)
        {
            oemInfo = oem;
        }

        public override string MessageAsyncPath
        {
            get { return OEM.Name + "/Home/TriggerMessageSent"; }
        }

        public override string GetUrlForMd5Check(ControllerBase controller)
        {
            string url = base.GetUrlForMd5Check(controller);
            url = url.Substring(OEM.Name.Length + 1);//截取到/oem
            return url;
        }

        #region IMembership

        public OEMMemberShip() : base()
        {

        }

        public override Type UserType
        {
            get { return typeof(SH3H.Api.Controllers.User); }
        }

        public override LoginUserStateType UserStateType
        {
            get { return LoginUserStateType.Redis; }
        }

        /// <summary>
        /// 读取获取设置Redis缓存Key
        /// </summary>
        /// <returns>处理后的key</returns>
        public override string OnRedisKey(string key)
        {
            //if (oemInfo == null) throw new QQZiFramework.NotAlowAccessException("oeminfo为空，请确保正确创建了DBContext实例！");
            if (oemInfo == null) return key;
            else return oemInfo.Name + "_" + key;
        }

        /// <summary>
        /// 读取获取设置系统缓存Key
        /// </summary>
        /// <returns>处理后的key</returns>
        public override string OnCacheKey(string key)
        {
            if (oemInfo == null) throw new QQZiFramework.NotAlowAccessException("oeminfo为空，请确保正确创建了DBContext实例！");
            return oemInfo.Name + "_" + key;
        }



        public override string UserToCookie(QQZiFramework.Membership.BaseUser u)
        {
            throw new NotImplementedException();
            //if (oemInfo == null) throw new QQZiFramework.NotAlowAccessException();
            //CookieUser cookieUser = new CookieUser(u, oemInfo.Name);
            //var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore };
            //string userJson = JsonConvert.SerializeObject(cookieUser, Newtonsoft.Json.Formatting.Indented, jSetting);
            //return QQZiFramework.Utility.Encrypt(userJson);
        }


        public override BaseUser GetCookieUser(string cookieValue)
        {
            throw new NotImplementedException();
            //string json = QQZiFramework.Utility.Decrypt(cookieValue);
            //return JsonConvert.DeserializeObject<CookieUser>(json) as BaseUser;
        }


        public override string OnUrlPermission(string url)
        {
            if (oemInfo == null) return url;
            int pos = url.IndexOf(oemInfo.Name + '/', StringComparison.OrdinalIgnoreCase);
            if (pos > -1)
            {
                return url.Substring(pos + oemInfo.Name.Length + 1);
            }
            else return url;
        }

        public override bool ResponseTraditional
        {
            get { return m_responseTraditional; }
        }

        internal static int Platform { get; set; }

        bool m_responseTraditional = false;


        public override T GetSettingValue<T>(DBContext context, string path, bool throwNoFoundError = false, T defaultVal = default(T))
        {
            T t = defaultVal;
            string val = null;
            if (OEM != null)
            {
                //查询数据库参数配置(首选) 
                ConfigParam configParam = GetDBConfigItem(context, path);
                if (configParam != null) val = configParam.ParamValue;

            }
            if (val == null)
            {
                if (OEM != null && OEM.AppSetting.TryGetValue(path, out t))
                {
                    return t;
                }
                //查询appsetting.json
                if (base.TryGetConfigValue(path, out t)) return t;

            }
            if (val != null)
            {
                t = (T)Convert.ChangeType(val, typeof(T));
            }
            else
            {
                if (throwNoFoundError) throw new Exception("找不到" + path + "的配置");
                else t = defaultVal;
            }
            return t;
        }



        protected override ILoggerRepository GetLogRepository()
        {
            if (oemInfo == null) return base.GetLogRepository();
            return LogManager.GetRepository(oemInfo.Name + "_Repository");
        }


        #endregion


        public override DBContext CreateDBContext()
        {
            System.Collections.Hashtable args = new System.Collections.Hashtable();
            args.Add("OEMInfo", OEM);
            return new DBContext(this.OEM.ProviderName, OEM.GetConnectionString(), null, this, args);
        }

        public override void OnActionExecuting(DBContext context, ActionExecutingContext filterContext, string Alias)
        {
            if (Platform == 1 && filterContext.RouteData.Values.ContainsKey("area"))
            {
                context.SetArgument("Route-DATA-AREA", filterContext.RouteData.Values["area"]);
            }
            base.OnActionExecuting(context, filterContext, Alias);
        }

        /// <summary>
        /// context释放
        /// </summary>
        /// <param name="context"></param>
        public virtual void OnDBContextDisposed(DBContext context)
        {
            base.OnDBContextDisposed(context);
        }

        
        
    }
}